// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2023-2024, Phytium Technology Co., Ltd.
 * This file describes the power management function.
 */

#include <common.h>
#include <command.h>
#include <asm/io.h>
#include <linux/arm-smccc.h>
#include "../cpu.h"
#include "../board_init/board.h"
#include "power_manage.h"
#include <e_uart.h>
#include "../parameter/parameter.h"

/*
 * Sends power management commands to the cpld
 */
void send_pwr_cmd(uint32_t cmd)
{
	switch (pm_get_power_manager()) {
	case 0:
		send_cpld_ctr(cmd);
		break;
	default:
		while (1);
	}
}

int get_s3_flag(void)
{
	uint32_t ret = 0;

	switch (pm_get_power_manager()) {
	case 0:
		ret = gpio_get_s3_flag();
		break;
	default:
		while (1);
	}

	return ret;
}

/*
 * scmi send core reset command
 */
void scmi_send_command_core_reset(void)
{
	p_printf("core reset start!\n");
	writel(0x1, AP_UBOOT_CONFIG);

	volatile mailbox_mem_e_t *mbx_mem = (mailbox_mem_e_t *)AP_TO_SCP_SHARED_MEM_BASE;

	/* build mailbox message */
	mbx_mem->msg_header = SCMI_MSG_CREATE_E(0x81, 0x0e, 0);
	mbx_mem->payload[0] = 0x0; // 0:disable; 1:enable
	mbx_mem->len = sizeof(mbx_mem->msg_header) + 4;
	mbx_mem->flags = 0x0;

	mbx_mem->status = 0x0;
	/* Initiate virtual channel communication */
	writel(mbx_mem->msg_header, AP_UBOOT_SET);
	while (1);
}

/*
 * scmi send gpio core reset command
 */
static void scmi_send_command_gpio_core_reset(void)
{
	p_printf("enable gpio core reset!\n");
	/* Mask the mailbox interrupt */
	writel(0x1, AP_UBOOT_CONFIG);

	volatile mailbox_mem_e_t *mbx_mem = (mailbox_mem_e_t *)AP_TO_SCP_SHARED_MEM_BASE;

	mbx_mem->msg_header = SCMI_MSG_CREATE_E(0x81, 0x12, 0);
	/* 0:disable; 1:enable */
	mbx_mem->payload[0] = 0x1;
	mbx_mem->len = sizeof(mbx_mem->msg_header) + 4;
	mbx_mem->flags = 0x0;

	mbx_mem->status = 0x0;
	/* Initiate virtual channel communication
	 * by corresponding the stat register to position 1
	 */
	writel(mbx_mem->msg_header, AP_UBOOT_SET);
}

/* s3 clean cmd */
void pwr_s3_clean(void)
{
	send_pwr_cmd(S3_CLEAN_CPLD);
}

void pwr_reboot(void)
{
	//send_pwr_cmd(REBOOT_CPLD);        //1.cpld power down
	p_printf("bmc warmreset\n");

	writel(0x10007, JPEG_ENCODER_BASE + JPEG_STATUS_INTERRUPT); //clear interrupt
	writel(0x0, JPEG_ENCODER_BASE + JPEG_TRANSFORM_INFORMATION); //disable jpeg
	p_printf("disable jpeg.\n");
	mdelay(1000);

	//writel(0x1, WDT0_BASE + WDT_WCS); //2.enable WDT0
	scmi_send_command_core_reset();     //3.core reset
}

/* vtt disable cmd */
void pwr_vtt_disable(void)
{
	send_pwr_cmd(VTT_DISABLE_CPLD);
}

/* vtt enable cmd */
void pwr_vtt_enable(void)
{
	send_pwr_cmd(VTT_ENABLE_CPLD);
}

/* s3 setup cmd */
void pwr_s3_setup(void)
{
	send_pwr_cmd(S3_SETUP_CPLD);
}

/* s3 shutdown cmd */
void pwr_shutdown(void)
{
	send_pwr_cmd(SHUTDOWN_CPLD);
}

/* bmc gpio core reset cmd */
void pwr_bmc_gpio_core_reset_enable(void)
{
	scmi_send_command_gpio_core_reset();
}

int oem_handler_callback_init(void)
{
	struct arm_smccc_res res;

	printf("&pwr_reboot = %p\n", &pwr_reboot);
	/* use standard smc call to handle the callback init */
	arm_smccc_smc(0xc300FFFA, (uint64_t)&pwr_reboot, 0x54461231, 0, 0, 0, 0, 0, &res);

	return 0;
}

int oem_handler_register(void)
{
	struct arm_smccc_res res;

	/* use standard smc call to handle the interrupt registration */
	arm_smccc_smc(0xc300FFFB, 72, 7, 0, 0, 0, 0, 0, &res);

	return 0;
}

//bmc gpio core reset handler
void pwr_bmc_gpio_core_reset_handler(void)
{
	p_printf("pwr bmc gpio core reset register!\n");
	oem_handler_register();
	oem_handler_callback_init();
}
